package storage

import (
	"context"
	"database/sql"
	"ia/common/support/global"
	"ia/common/support/tools"
	"log"
	"os"
	"reflect"
	"time"

	"github.com/kataras/golog"
	"github.com/yitter/idgenerator-go/idgen"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
)

var GDB1 *gorm.DB
var GDB2 *gorm.DB

func InitGDb1() {
	db := conn(global.GConfig.DB.Mysql.Db1)
	GDB1 = db
}

func InitGDb2() {
	db := conn(global.GConfig.DB.Mysql.Db2)
	GDB2 = db
}

func conn(info global.DBInfo) *gorm.DB {
	var (
		err   error
		db    *gorm.DB
		sqlDB *sql.DB
		// dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	)
	if db, err = gorm.Open(mysql.Open(global.GConfig.DBConnUrl(info)), &gorm.Config{
		DisableForeignKeyConstraintWhenMigrating: true, // 迁移数据库表时禁用外键约束
		Logger: logger.New(
			log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
			logger.Config{
				SlowThreshold: time.Second, // Slow SQL threshold
				// LogLevel:      logger.Error, // Log level
				LogLevel:                  logger.Info, // Log level
				IgnoreRecordNotFoundError: true,        // Ignore ErrRecordNotFound error for logger
				Colorful:                  true,        // Disable color
			}),
		// 命名约定
		NamingStrategy: schema.NamingStrategy{
			TablePrefix:   "",
			SingularTable: true, // 一个坑，不设置这个参数，gorm会把表名转义后加个s，导致找不到数据库的表
		},
	}); err != nil {
		goto ERR
	}
	if sqlDB, err = db.DB(); err != nil {
		goto ERR
	}
	sqlDB.SetMaxOpenConns(info.MaxOpenConns)
	sqlDB.SetConnMaxIdleTime(time.Duration(info.MaxIdleConns))
	//data, _ := json.Marshal(sqlDb.Stats()) //获得当前的SQL配置情况

	// gstps://www.klsf.cc/archives/25
	// 全局注册，将时间变成字符串
	if err = db.Callback().Create().Before("gorm:create").Register("create_before", createBefore); err != nil {
		goto ERR
	}
	if err = db.Callback().Update().Before("gorm:update").Register("update_before", updateBefore); err != nil {
		goto ERR
	}
	//db.Callback().Delete().Before("gorm:delete").Register("my_plugin:deleted_time", deleteBefore)
	db.Debug()
	return db
ERR:
	golog.Fatalf("~~> MYSQL[gorm]启动失败!原因:%s", err.Error())
	return nil
}

func createBefore(db *gorm.DB) {
	if db.Statement.Schema != nil {
		for _, field := range db.Statement.Schema.Fields {
			switch db.Statement.ReflectValue.Kind() {
			case reflect.Slice, reflect.Array:
				for i := 0; i < db.Statement.ReflectValue.Len(); i++ {
					if field.Name == "Id" {
						if err := field.Set(context.Background(), db.Statement.ReflectValue.Index(i), idgen.NextId()); err != nil {
							golog.Errorf("Struct(Id): grom global callback err:%v", err)
						}
					}
					if field.Name == "CreatedTime" {
						tt := tools.CurrentTimeString()
						if err := field.Set(context.Background(), db.Statement.ReflectValue.Index(i), tt); err != nil {
							golog.Errorf("Slice(CreatedTime): grom global callback err:%v", err)
						}
					}
				}
			case reflect.Struct:
				if field.Name == "Id" {
					if err := field.Set(context.Background(), db.Statement.ReflectValue, idgen.NextId()); err != nil {
						golog.Errorf("Struct(Id): grom global callback err:%v", err)
					}
				}
				if field.Name == "CreatedTime" {
					if err := field.Set(context.Background(), db.Statement.ReflectValue, tools.CurrentTimeString()); err != nil {
						golog.Errorf("Struct(CreatedTime): grom global callback err:%v", err)
					}
				}
			}
		}
	}
}

func updateBefore(db *gorm.DB) {
	if db.Statement.Schema != nil {
		if field := db.Statement.Schema.LookUpField("UpdatedTime"); field != nil {
			if err := field.Set(context.Background(), db.Statement.ReflectValue, tools.CurrentTimeString()); err != nil {
				golog.Errorf("grom global callback 【updateBefore】err:%v", err)
			}
		}
	}
}

// func deleteBefore(db *gorm.DB) {
// 	if db.Statement.Schema != nil {
// 		if field := db.Statement.Schema.LookUpField("DeletedTime"); field != nil {
// 			field.Set(db.Statement.ReflectValue, tools.CurrentTimeString())
// 		}
// 	}
// }
